cover picture sponsor: gleammming.art
在開發程式的過程中,我們時常會需要處理資料的問題,而整個存取資料的過程就好像倉儲業者一樣:
司機:「我這邊有一個東西要送到市政府,便條紙上說代號是
富士山
,我需要裡面的東西。」
配送員:「好喔!我找一下,代號叫做
富士山
是吧?我查一下它的位置……它的位置是 021。」
接著配送員走進倉庫編號 021 的位置並打開了箱子,裡面是一個蘋果。
配送員:「給你,裡面是一個蘋果!」
司機:「好的,那我要出發了!」
在 JavaScript 中,我們可以透過 var
關鍵字來宣告一個變數:
var box;
接著在程式執行期的創造階段時,解析器會透過一張記著識別字的大表,來確認先前有沒有同樣的識別字:
如果之前還沒宣告過,那麼解析器就會接著將識別字 box
所存的地址 指向 一個沒用過的記憶體地址(例如:0x00)給這個識別字,並且初始化一個值 undefined
。
如果已經使用 var
宣告過的話,那麼他將不會影響原有的記憶體位置。
但如果你是使用 ES6 中的
const
重複宣告變數的話,引擎會提示你該變數已經被宣告過了。
在宣告完變數後,接下來如果你想要透過變數儲存資料的話,我們可以藉由 =
賦值運算符(Assignment Operator) 來幫我們達成:
var box = 'Gorilla!';
「但是……那不是等號嗎?」
抱持著數學家的眼光,你可能會感到疑惑。但我很遺憾且必須鄭重的告訴你說:「那不是等號,千萬不要這樣理解。」因為 =
這個符號在程式語言中多半是 「賦予某個值」 的概念。
而回到上方的程式碼中,一開始我們如同宣告變數時的規則,一樣會先分配好一個記憶體:
在初始化完畢後,接著解析器才會幫我們做後續賦值的行為,而當解析器在賦值時,它會 重新分配 一個新的記憶體地址並將值放入其中,再將變數原先指向 0x00
的指標改為指向 0x01
:
如果後續又有重新賦值的行為的話,就會如上方流程一樣再重新分配一個新的記憶體地址給它。
某個記憶體地址沒有被任何變數所參考到的話,在瀏覽器上會自動被記憶體垃圾回收機制所自動處理掉,所以你可以不用擔心
0x00
將來的處置。(詳見後續的 垃圾回收機制 章節)
若是直接將值賦值給變數皆會重新分配記憶體地址,倘若是透過 變數賦值給另一個變數 時則會有另一個機制處理,詳見資料型別章節。
現在我們會宣告變數也會儲存值進去了,如果你想要找回這個資料,你可以透過 變數名稱 再次尋找到它:
var box;
console.log(box); // undefined
在上面程式碼中的第二行中,解析器會先去表中尋找 box
所指向的記憶體位置,並回傳指向記憶體地址中的值。
而這時我們可以透過 console.log(放入你想印出的值)
,將值印到瀏覽器中的開發者工具列上。
另外,倘若試著取得未宣告的變數時,引擎會拋出一個錯誤來提示你:
anotherBox; // Uncaught ReferenceError: anotherBox is not defined
在數學領域中
LHS
意思即為等號的左邊(Left Hand Side),RHF
則為等號的右邊(Right Hand Side);而對於 JavaScript 來說就如同找址
與找值
。
現在我們已經會宣告變數、儲存資料與讀取資料了,而在 JavaScript 當中,懂得區分什麼時候是 找址
,什麼時候是 找值
是一件很重要的事情,我們用一個簡單的例子來舉例:
var box = 1;
console.log(box)
在第一行中 box = 1
的 box
主要用意是為了找到 box
的所指的 記憶體位置,並把 1
放進去,也就是說 LHS 關注的是該變數所指的是 哪個記憶體。
而第二行 console.log(box)
中的 box
是為了找到其記憶體中的 值,並把它顯示出來,也就是說 RHS 關注的是該變數所指的記憶體中的 值是什麼。
接下來的幾個章節中陸陸續續會再次遇到 找址
跟 找值
的議題,若你閱讀到後面忘記時,不彷回來再看看這兩者的差別。
有關於變數的命名可以參考下列兩個基本指標:
_
、錢字號 $
與數字等等來替變數命名var
)。box
跟 BOX
)命名風格的部分有以下幾種:
var firstName;
var lastName;
var FirstName;
var LastName;
var first_name;
var last_name;
至於選用哪種,請依照團隊的開發習慣作為考量;最後,還有另一種比較特別的是全大寫心法:
var PI = 3.1415926;
這種命名方法通常出現在常量的數值,也就是一個固定值,也就是說我們平常不會去更動它的值,主要是為了取這個值來進行運算,而透過這樣的命名心法我們會自然而然的不會去任意的更動它!(當然,你也可以使用 ES6 中的 const
來宣告常數)。
以上的的命名規範與命名風格只能算是基礎該做的,而接下來往後幾個章節會陸陸續續會再強化這一塊的概念!
目標:瞭解變數存取值的機制。
請試著透過這張樹狀圖或你自製的圖表回想這章節的概念:
為了能夠更輕易瞭解變數的存取上面的記憶體模型有經過簡化。
- 想從
stack
、heap
角度上理解變數的可參考:棧內存 (Stack) & 堆內存 (Heap)- 想從
Bytecode
角度上理解變數的可參考:從變數看 bytecode